package com.hewanglan.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.hewanglan.subject.common.enums.IsDeletedFlagEnum;
import com.hewanglan.subject.domain.bo.SubjectCategoryBO;
import com.hewanglan.subject.domain.bo.SubjectLabelBO;
import com.hewanglan.subject.domain.convert.SubjectCategoryConverter;
import com.hewanglan.subject.domain.service.SubjectCategoryDomainService;
import com.hewanglan.subject.domain.util.CacheUtil;
import com.hewanglan.subject.infra.basic.entity.SubjectCategory;
import com.hewanglan.subject.infra.basic.entity.SubjectLabel;
import com.hewanglan.subject.infra.basic.entity.SubjectMapping;
import com.hewanglan.subject.infra.basic.service.SubjectCategoryService;
import com.hewanglan.subject.infra.basic.service.SubjectLabelService;
import com.hewanglan.subject.infra.basic.service.SubjectMappingService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainService {
    @Resource
    private SubjectCategoryService subjectCategoryService;

    @Resource
    private SubjectMappingService subjectMappingService;

    @Resource
    private SubjectLabelService subjectLabelService;

    @Resource
    private ThreadPoolExecutor labelThreadPool;

    @Resource
    private CacheUtil cacheUtil;

    //    @Override
//    public void add(SubjectCategoryBO subjectCategoryBO) {
//        if (log.isInfoEnabled()) {
//            log.info("SubjectCategoryController.add.bo:{}", JSON.toJSONString(subjectCategoryBO));
//        }
//        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBOToCategory(subjectCategoryBO);
//        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
//        subjectCategoryService.insert(subjectCategory);
//    }
    @Override
    public void add(SubjectCategoryBO subjectCategoryBO) {
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryController.add.bo:{}", JSON.toJSONString(subjectCategoryBO));
        }
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBOToCategory(subjectCategoryBO);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        subjectCategoryService.insert(subjectCategory);

    }

    //    @Override
//    public List<SubjectCategoryBO> queryCategory(SubjectCategoryBO subjectCategoryBO) {
//        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBOToCategory(subjectCategoryBO);
//        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
//        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
//        List<SubjectCategoryBO> boList = SubjectCategoryConverter.INSTANCE.convertBOToCategory(subjectCategoryList);
//        if (log.isInfoEnabled()) {
//            log.info("SubjectCategoryController.queryPrimaryCategory.boList:{}", JSON.toJSONString(boList));
//        }
//        boList.forEach(bo -> {
//            Integer subjectCount = subjectCategoryService.querySubjectCount(bo.getId());
//            bo.setCount(subjectCount);
//        });
//
//        return boList;
//    }
    @Override
    public List<SubjectCategoryBO> queryCategory(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBOToCategory(subjectCategoryBO);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
        List<SubjectCategoryBO> boList = SubjectCategoryConverter.INSTANCE.convertBOToCategory(subjectCategoryList);
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryController.queryCategory.boList:{}", JSON.toJSONString(boList));
        }
        boList.forEach(bo -> {
            Integer subjectCount = subjectCategoryService.querySubjectCount(bo.getId());
            bo.setCount(subjectCount);
        });
        return boList;
    }

    //    @Override
//    public Boolean update(SubjectCategoryBO subjectCategoryBO) {
//        SubjectCategory subjectCategory = SubjectCategoryConverter.
//                INSTANCE.convertBOToCategory(subjectCategoryBO);
//        //更新操作影响的行数
//        int count = subjectCategoryService.update(subjectCategory);
//        return count > 0;
//    }
    @Override
    public Boolean update(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBOToCategory(subjectCategoryBO);
        int count = subjectCategoryService.update(subjectCategory);
        return count > 0;
    }

    //    @Override
//    public Boolean delete(SubjectCategoryBO subjectCategoryBO) {
//        SubjectCategory subjectCategory = SubjectCategoryConverter.
//                INSTANCE.convertBOToCategory(subjectCategoryBO);
//
//        subjectCategory.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode());
//
//        int count = subjectCategoryService.update(subjectCategory);
//        return count > 0;
//    }
    @Override
    public Boolean delete(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBOToCategory(subjectCategoryBO);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode());
        int count = subjectCategoryService.update(subjectCategory);
        return count > 0;
    }

    //    @Override
//    @SneakyThrows
//    public List<SubjectCategoryBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) {
//        /**
//         * 查询当前一级分类下所有二级分类
//         * 此次查询数据量较大，会花费较多时间，
//         * 避免多次查询，可将首次查询的结果放入缓存中，并设置缓存有效期
//         * 之后查询时，若缓存里有，则从缓存里拿，没有则查数据库并放入缓存中
//         */
//
//        Long id = subjectCategoryBO.getId();
//        String cacheKey = "categoryAndLabel." + subjectCategoryBO.getId();
//        List<SubjectCategoryBO> subjectCategoryBOS = cacheUtil.getResult(cacheKey,
//                SubjectCategoryBO.class, (key) -> getSubjectCategoryBOS(id));
//        return subjectCategoryBOS;
//    }
    @Override
    @SneakyThrows
    public List<SubjectCategoryBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) {
        Long id = subjectCategoryBO.getId();
        String cacheKey = "categoryAndLabel" + id;
        List<SubjectCategoryBO> subjectCategoryBOS = cacheUtil.getResult(cacheKey,
                SubjectCategoryBO.class, (key) -> getSubjectCategoryBOS(id));
        return subjectCategoryBOS;
    }

    /**
     * 查询二级分类以及各个二级分类的标签信息
     *
     * @param categoryId
     * @return
     */
//    private List<SubjectCategoryBO> getSubjectCategoryBOS(Long categoryId) {
//        SubjectCategory subjectCategory=new SubjectCategory();
//        subjectCategory.setParentId(categoryId);
//        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
//        //存储所有二级分类
//        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
//        if (log.isInfoEnabled()) {
//            log.info("SubjectCategoryController.queryCategoryAndLabel.subjectCategoryList:{}",
//                    JSON.toJSONString(subjectCategoryList));
//        }
//        List<SubjectCategoryBO> categoryBOList=SubjectCategoryConverter.INSTANCE.convertBOToCategory(subjectCategoryList);
//        /**
//         * 以下是采用completablefuture方法
//         */
//        /**
//         * key对应的是二级分类的id
//         * value为该二级分类的标签信息
//         */
//        Map<Long,List<SubjectLabelBO>> map=new HashMap<>();
//        List<CompletableFuture<Map<Long, List<SubjectLabelBO>>>> completableFutureList = categoryBOList.stream().map(category ->
//                CompletableFuture.supplyAsync(() -> getSubjectLabelBOS(category), labelThreadPool)
//        ).collect(Collectors.toList());
//        completableFutureList.forEach(future->{
//            try{
//                Map<Long,List<SubjectLabelBO>> resultMap=future.get();
//                map.putAll(resultMap);
//            }catch (Exception e){
//                e.printStackTrace();
//            }
//        });
//
//        /**
//         * 以下是采用futuretask方法
//         */
////        //获取每个二级分类的所有标签
////        //采用多线程异步查询每个二级分类下的标签
////        List<FutureTask<Map<Long,List<SubjectLabelBO>>>> futureTaskList=new LinkedList<>();
////        //线程池并发调用
////        Map<Long,List<SubjectLabelBO>> map=new HashMap<>();
////        categoryBOList.forEach(category->{
////            FutureTask<Map<Long,List<SubjectLabelBO>>> futureTask=new FutureTask<>(()->
////                getSubjectLabelBOS(category)
////            );
////            futureTaskList.add(futureTask);
////            labelThreadPool.submit(futureTask);
////
////        });
////
////        for (FutureTask<Map<Long, List<SubjectLabelBO>>> futureTask : futureTaskList) {
////            Map<Long, List<SubjectLabelBO>> resultMap = futureTask.get();
////            if(CollectionUtils.isEmpty(resultMap))
////            {
////                continue;
////            }
////            map.putAll(resultMap);
////        }
//        categoryBOList.forEach(categoryBO->{
//            categoryBO.setLabelBOList(map.get(categoryBO.getId()));
//        });
//        return categoryBOList;
//    }
    private List<SubjectCategoryBO> getSubjectCategoryBOS(Long categoryId) {//一级分类ID
        SubjectCategory subjectCategory = new SubjectCategory();
        subjectCategory.setParentId(categoryId);
        subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryController.queryCategoryAndLabel.getSubjectCategoryBOS.subjectCategoryList:{}",
                    JSON.toJSONString(subjectCategoryList));
        }
        //存储二级分类的信息
        List<SubjectCategoryBO> categoryBOList = SubjectCategoryConverter.INSTANCE.
                convertBOToCategory(subjectCategoryList);

        Map<Long, List<SubjectLabelBO>> map = new HashMap<>();
        List<CompletableFuture<Map<Long, List<SubjectLabelBO>>>> completableFutureList = categoryBOList.stream().map(category ->
                CompletableFuture.supplyAsync(() -> getSubjectLabelBOS(category), labelThreadPool)
        ).collect(Collectors.toList());

        completableFutureList.forEach(future -> {
            try {
                Map<Long, List<SubjectLabelBO>> resultMap = future.get();
                map.putAll(resultMap);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        categoryBOList.forEach(categoryBO -> {
            categoryBO.setLabelBOList(map.get(categoryBO.getId()));
        });
        return categoryBOList;
    }


    private Map<Long, List<SubjectLabelBO>> getSubjectLabelBOS(SubjectCategoryBO category) {
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryController.queryCategoryAndLabel.getSubjectLabelBOS.bo:{}", JSON.toJSONString(category));
        }
        Map<Long, List<SubjectLabelBO>> labelMap = new HashMap<>();

        SubjectMapping subjectMapping = new SubjectMapping();
        subjectMapping.setCategoryId(category.getId());
        List<SubjectMapping> mappingList = subjectMappingService.queryLabelId(subjectMapping);
        if (mappingList.isEmpty()) {
            return null;
        }
        List<Long> labelIdList = mappingList.stream().map(SubjectMapping::getLabelId).collect(Collectors.toList());
        List<SubjectLabel> labelList = subjectLabelService.batchQueryById(labelIdList);

        List<SubjectLabelBO> labelBOList = new ArrayList<>();
        labelList.forEach(label -> {
            SubjectLabelBO subjectLabelBO = new SubjectLabelBO();
            subjectLabelBO.setId(label.getId());
            subjectLabelBO.setLabelName(label.getLabelName());
            subjectLabelBO.setCategoryId(label.getCategoryId());
            subjectLabelBO.setSortNum(label.getSortNum());
            labelBOList.add(subjectLabelBO);
        });

        labelMap.put(category.getId(), labelBOList);
        return labelMap;
    }
}
